using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using MainGame.Menu;
using Services;
using MainGame.GamePlay;
using MainGame.GameSound;
using XNAGame.Menu;


namespace MainGame.StateManagement
{
  /// <summary>
  /// Una lista che mantiene i punteggi di tutti i giocatori per ogni round di gioco
  /// </summary>
  public struct PartialScores
  {
    public static List<Score> scoreList;
  }

  /// <summary>
  /// Funzioni statiche (invocabili da una qualsiasi istanza di Game) che si
  /// occupano di attivare i componenti che caratterizzano ciascuna fase di gioco
  /// </summary>
  public static class StateManager
  {

    private static MainMenu mainMenu;
    private static SettingsMenu settingsMenu;
    private static StartMenu startMenu;
    public static CreditsMenu creditsMenu;
    public static HelpMenu helpMenu;
    public static BackgroundMenu bgMenu;
    
    /// <summary>
    /// Avviamo il menu: servono solo due componenti, MenuComponent e InputManager
    /// </summary>
    /// <param name="game"></param>
    static public void StartMenu(this Game game)
    {
      game.Cleanup();
      game.Components.Add(new InputManager(game));
      startMenu = new StartMenu(game, MenuDepths.FrontMenu);
      game.Components.Add(startMenu);
      mainMenu = new MainMenu(game, MenuDepths.FrontMenu);
      game.Components.Add(mainMenu);
      settingsMenu = new SettingsMenu(game, MenuDepths.MiddleMenu);
      game.Components.Add(settingsMenu);
      creditsMenu = new CreditsMenu(game, MenuDepths.BackMenu);
      game.Components.Add(creditsMenu);
      bgMenu = new BackgroundMenu(game, MenuDepths.Background);
      game.Components.Add(bgMenu);
      game.Components.Add(new MenuSoundManager(game));
      var menu = game.Services.GetService(typeof(IMainMenu)) as IMainMenu;
      var startmenu = game.Services.GetService(typeof(IStartMenu)) as IStartMenu;
      creditsMenu.Enabled = false;
      settingsMenu.Enabled = false;
      startmenu.OnPlayClicked += () => game.StartLevel(1);
      startmenu.OnExitClicked += () => game.Exit();
      menu.OnSettingsClicked += () => game.ShowSettings();
      menu.OnCreditsClicked += () => game.ShowCredits();
      menu.OnHelpClicked += () => game.ShowHelp();
    }

    static public void ShowSettings(this Game game)
    {
      game.Cleanup();
      game.Components.Add(new InputManager(game));
      mainMenu = new MainMenu(game, MenuDepths.FrontMenu);
      game.Components.Add(mainMenu);
      settingsMenu = new SettingsMenu(game, MenuDepths.MiddleMenu);
      game.Components.Add(settingsMenu);
      creditsMenu = new CreditsMenu(game, MenuDepths.BackMenu);
      game.Components.Add(creditsMenu);
      bgMenu = new BackgroundMenu(game, MenuDepths.Background);
      game.Components.Add(bgMenu);
      mainMenu.Enabled = false;
      settingsMenu.Animated = true;
      creditsMenu.Enabled = false;      
      game.Components.Add(new MenuSoundManager(game));      
      var menu = game.Services.GetService(typeof(ISettingsMenu)) as ISettingsMenu;
      menu.OnSBackClicked += () => game.StartMenu();

    }


    static public void ShowCredits(this Game game)
    {
      game.Cleanup();
      game.Components.Add(new InputManager(game));
      mainMenu = new MainMenu(game, MenuDepths.FrontMenu);
      game.Components.Add(mainMenu);
      settingsMenu = new SettingsMenu(game, MenuDepths.MiddleMenu);
      game.Components.Add(settingsMenu);
      creditsMenu = new CreditsMenu(game, MenuDepths.BackMenu);
      game.Components.Add(creditsMenu);
      bgMenu = new BackgroundMenu(game, MenuDepths.Background);
      game.Components.Add(bgMenu);
      creditsMenu.Animated = true;
      mainMenu.Enabled = false;
      settingsMenu.Enabled = false;      
      game.Components.Add(new MenuSoundManager(game));
      var menu = game.Services.GetService(typeof(ICreditsMenu)) as ICreditsMenu;
      menu.OnCBackClicked += () => game.StartMenu();

    }

    static public void ShowHelp(this Game game)
    {
      game.Cleanup();
      game.Components.Add(new InputManager(game));
      helpMenu = new HelpMenu(game, MenuDepths.ForeGround);
      game.Components.Add(helpMenu);
      startMenu = new StartMenu(game, MenuDepths.FrontMenu);
      game.Components.Add(startMenu);
      mainMenu = new MainMenu(game, MenuDepths.FrontMenu);
      game.Components.Add(mainMenu);
      settingsMenu = new SettingsMenu(game, MenuDepths.MiddleMenu);
      game.Components.Add(settingsMenu);
      creditsMenu = new CreditsMenu(game, MenuDepths.BackMenu);
      game.Components.Add(creditsMenu);
      bgMenu = new BackgroundMenu(game, MenuDepths.Background);
      game.Components.Add(bgMenu);
      helpMenu.Animated = true;
      mainMenu.Enabled = false;
      creditsMenu.Enabled = false;      
      settingsMenu.Enabled = false;
      mainMenu.Enabled = false;
      game.Components.Add(new MenuSoundManager(game));
      var menu = game.Services.GetService(typeof(IHelpMenu)) as IHelpMenu;
      menu.OnHBackClicked += () => game.StartMenu();

    }
   
    /// <summary>
    /// Avviamo un livello; ci servono vari componenti:
    /// <list type="">
    /// <item>input manager per gestire gli eventi di input</item>
    /// <item>ui per disegnare l'interfaccia utente</item>
    /// <item>board renderer per disegnare le carte correnti</item>
    /// <item>board manager per gestire la logica delle carte, le
    /// AI, i giocatori umani, i turni, etc.</item>
    /// </list>
    /// 
    /// Il board_manager si occupa di lanciare due eventi che denotano la conclusione
    /// della partita; in relazione a tali eventi, lanciamo alternativamente il menu 
    /// oppure la schermata di recap del punteggio di fine partita.
    /// </summary>
    /// <param name="game"></param>
    /// <param name="index"></param>
    static private void StartLevel(this Game game, int index)
    {
      game.Cleanup();
      var input_manager = new InputManager(game);
      var ui_renderer = new UIRenderer(game);
      var board_renderer = new BoardRenderer(game);
      var board_manager = new GamePlayLayer(game);
      game.Components.Add(input_manager);
      game.Components.Add(ui_renderer);
      game.Components.Add(board_renderer);
      game.Components.Add(board_manager);
      game.Components.Add(new GamePlaySoundManager(game));
      var level_manager = game.Services.GetService(typeof(ILevelManager<Score>)) as ILevelManager<Score>;

      level_manager.OnLevelLost += () => game.StartMenu();
      level_manager.OnLevelWon += score => game.LevelRecapScreen(index, score);
    }

    /// <summary>
    /// La schermata di recap di fine partita mostra i punteggi dei giocatori; tale
    /// schermata richiede l'input, che usa per lanciare l'evento Exit (se l'utente
    /// clicca sul bottone exit della schermata) oppure l'evento Continue (analogo
    /// ad Exit)
    /// </summary>
    /// <param name="game"></param>
    /// <param name="index"></param>
    /// <param name="score"></param>
    static private void LevelRecapScreen(this Game game, int index, Score score)
    {
      game.Cleanup();

      var input_manager = new InputManager(game);
      var level_recap = new LevelRecapScreen(game, score);
      level_recap.OnExit += () => game.StartMenu();
      level_recap.OnContinue += () => game.StartLevel(index + 1);
      game.Components.Add(level_recap);
      game.Components.Add(input_manager);
    }

    //static bool first_transition = true;

    /// <summary>
    /// Per evitare interferenze tra una fase di gioco e l'altra, cancelliamo tutti
    /// i game components attivi al termine di ciascuna fase di gioco.
    /// </summary>
    /// <param name="game"></param>
    static private void Cleanup(this Game game)
    {
      //TransitionScreen transition = null;
      //if(first_transition == false)
      //  transition = new TransitionScreen(game);
      for (int i = 0; i < game.Components.Count; i++)
      {
        ((GameComponent)game.Components[i]).Dispose();
        i--;
      }
      game.Components.Clear();
      //if (first_transition == false)
      //  game.Components.Add(transition);
      //else
      //  first_transition = false;
    }
  }
}
